#include "iotgo_platformAPI.h"
#include "iotgo_service.h"
#include "iotgo_memory_hooks.h"
#include "iotgo_mySocketClient_interface.h"
#include "custom_data_type.h"
#include "cJSON.h"
#include "stdint.h"


/*state*/
#define POST_IS_NOT_STARTED     0
#define POST_SOCKET_IS_INITED   1
#define POST_CONNECTION_IS_DONE 2

/*general*/
#define POST_DOMAIN_LEN 50

/*return error*/
#define ERROR_SUCCESS               0
#define ERROR_NOT_FINISHED         -1
#define ERROR_SOCKET_SETUP         -2
#define ERROR_CONNECTION           -3
#define ERROR_POST                 -4
#define ERROR_INVALID_STATE        -5

static volatile int state = POST_IS_NOT_STARTED;
static uint8_t post_url[80] = {0};

static MySocketClient *p_socket = NULL;

static uint8_t  post_domain[POST_DOMAIN_LEN] = "54.223.98.144";
static uint32_t post_port = 443;
static uint8_t subPath[30]= "/otaother/storeStatus";

static UPDATE_CLOUD_RESULT post_result;

static int8_t parseUrl(void)
{
    int8_t *http = NULL;
    int8_t *ip = NULL;
    int8_t *port = NULL;
    int8_t *path = NULL;
    int8_t tmp[5] = {0};
    int ip_len = 0;
    int port_len = 0;
    int path_len = 0;
    int i = 0;

    printf("[%s] the url to be parsed is [%s]\n",__FUNCTION__,post_url);
    http = strstr(post_url,"https://");
    if(http)
    {
	ip = http + 8;
	port = strstr(ip,":");
	if(port)
	{
	    ip_len = port - ip;
	    memcpy(post_domain,ip,ip_len);
	    printf("[%s] post_domain is %s\n",__FUNCTION__,post_domain);
	    port = port + 1;
	    path = strstr(port,"/");
	    if(path)
	    {
		port_len = path -port;
		memcpy(tmp,port,port_len);
		post_port = atoi(tmp);
		printf("[%s] post port is [%d]\n",__FUNCTION__,post_port);
		memcpy(subPath,path,strlen(path));
		printf("[%s] path is %s\n",__FUNCTION__,subPath);
		return 0;
	    }
	}
	else
	{
	    post_port = 8080;
	    printf("[%s] no port found ,use default:[%d]\n",__FUNCTION__,post_port);
	    path = strstr(ip,"/");
	    if(path)
	    {
		ip_len = path - ip;
		memcpy(post_domain,ip,ip_len);
		printf("[%s] post_domain is %s\n",__FUNCTION__,post_domain);
		memcpy(subPath,path,strlen(path));
		printf("[%s] path is %s\n",__FUNCTION__,subPath);
		return 0;
	    }
	    else
	    {
		printf("[%s] no sub path found\n",__FUNCTION__,post_port);
	    }
	}
    }
    else
    {
	printf("[%s] no 'http' in post_url\n",__FUNCTION__);
    }
	
    return -1;
}

static void cleanPostAction(void)
{
    cleanSocketClient(&p_socket);
    state = POST_IS_NOT_STARTED;
}

static int8_t postCloudResult(void)
{
    cJSON *cjson_params = NULL;
    int8_t *param = NULL;
    uint8_t buf[1024] = {0};
    uint8_t deviceID[STRING_DEVICE_ID_LEN] = "wrong ID!";
    uint8_t apikey[STRING_API_KEY_LEN] = "wrong apikey!";
    uint8_t user_apikey[STRING_API_KEY_LEN] = "wrong apikey";
    UPDATE_CLOUD_RESULT *pResult = &post_result;
    int32_t ret;

    printf("[%s] entry postCloudResult\n",__FUNCTION__);
    ret = getDeviceInfo(deviceID,apikey);
    ret = iotgoReadUserApiKey(user_apikey);
    cjson_params = cJSON_CreateObject();
    if(cjson_params)
    {
		printf("[%s] set up data\n",__FUNCTION__);
	
		cJSON_AddItemToObject(cjson_params ,"deviceid" ,cJSON_CreateString(deviceID));
		cJSON_AddItemToObject(cjson_params ,"apikey" ,cJSON_CreateString(user_apikey));
		cJSON_AddItemToObject(cjson_params ,"bucketName" ,cJSON_CreateString(pResult->bucketName));
		cJSON_AddItemToObject(cjson_params ,"filePath" ,cJSON_CreateString(pResult->filePath));
		cJSON_AddItemToObject(cjson_params ,"fileSize" ,cJSON_CreateNumber(pResult->fileSize));
		cJSON_AddItemToObject(cjson_params ,"uploadTime" ,cJSON_CreateNumber(pResult->uploadTime));
		cJSON_AddItemToObject(cjson_params ,"storetype" ,cJSON_CreateNumber(pResult->storetype));
		cJSON_AddItemToObject(cjson_params ,"ts" ,cJSON_CreateNumber(pResult->ts));
		cJSON_AddItemToObject(cjson_params ,"sign" ,cJSON_CreateString(pResult->sign));
		cJSON_AddItemToObject(cjson_params ,"eventid" ,cJSON_CreateString(pResult->eventid));

		param = (int8_t *)cJSON_PrintUnformatted(cjson_params);
		printf("[%s] param is %s\n",param);

		printf("[%s] param len is %d\n",__FUNCTION__,strlen(param));
		ret = sprintf(buf,"POST /otaother/storeStatus HTTP/1.1\r\n"
		      "HOST: %s\r\n"
		      "Content-Type: application/json\r\n"
		      "Content-Length: %d\r\n\r\n%s",
		      post_domain,
		      strlen(param),
		      param);

		printf("[%s] write buf is \n%s\n",__FUNCTION__,buf);
		ret = writeToServer(p_socket,buf,ret);
		printf("[%s] write len is %d\n",__FUNCTION__,ret);
        if(param)
        {
            pFree(param);
        }
        if(cjson_params)
        {
            cJSON_Delete(cjson_params);
		}
		memset(buf,0,1024);
		ret = readFromServer(p_socket,buf,1024);
		printf("[%s] readFromServer return is %d\n",__FUNCTION__,ret);
		printf("[%s] read buf is \n%s\n",__FUNCTION__,buf);
		if(ret > 0)
		{
			printf("[%s] return success\n",__FUNCTION__);
			return 0;
		}
    }
    return -1;
}


static int8_t post_runtime(void)
{

    int8_t ret = -1;
    switch(state)
    {
    case POST_IS_NOT_STARTED:
	ret = parseUrl();
	if(ret == 0)
	{
	    printf("[%s] parse url done\n",__FUNCTION__);
	    p_socket = setupSocketClient(post_domain,post_port);
	}
	else
	{
	    printf("[%s] parse url fail\n",__FUNCTION__);
	}

	if(p_socket)
	{
	    state = POST_SOCKET_IS_INITED;
	    ret = ERROR_NOT_FINISHED;
	}
	else
	{
	    printf("[%s] p_socket setup fail\n",__FUNCTION__);
	    cleanPostAction();
	    ret = ERROR_SOCKET_SETUP;
	}
	break;
    case POST_SOCKET_IS_INITED:
	printf("[%s] connect to server\n",__FUNCTION__);
	ret = connectToServer(p_socket);
	if(ret == MYSOCKETCLIENT_SUCCESS)
	{
	    state = POST_CONNECTION_IS_DONE;
	    ret = ERROR_NOT_FINISHED;
	}
	else if(ret == MYSOCKETCLIENT_FAIL)
	{
	    ret = ERROR_CONNECTION;
	}
	else
	{
	    ret = ERROR_NOT_FINISHED;
	}
	break;
    case POST_CONNECTION_IS_DONE:
	printf("[%s] post the result\n",__FUNCTION__);
	ret = postCloudResult();
	printf("[%s] postCloudResult return is %d\n",__FUNCTION__,ret);

	if(ret == ERROR_SUCCESS)
	{
	    cleanPostAction();
	    return ERROR_SUCCESS;
	}
	else
	{
	    ret = ERROR_POST;
	    state = POST_SOCKET_IS_INITED;
	}
	break;
    default:
	ret = ERROR_INVALID_STATE;
	break;
    }
    return ret;
}


void storeCloudResultPostUrl(uint8_t *str)
{
    memset(post_url,0,80);
    memcpy(post_url,str,strlen(str));
    printf("[%s] post_url is %s\n",__FUNCTION__,post_url);
}

int8_t iotgoUpdateCloudStoreDone(void *pstruct)
{
    int8_t ret;
    int8_t count = 0;
    int8_t iotgo_state = IOTGO_IDLE;

    iotgo_state = iotgoGetState();
    if(iotgo_state != IOTGO_REGISTER_IS_READY)
    {
	printf("[%s][warn]iotgo connection is not ready\n",__FUNCTION__);
	return -1;
    }

    memset(&post_result,0,sizeof(post_result));
    memcpy(&post_result,pstruct,sizeof(post_result));
    while(1)
    {
	ret = post_runtime();
	if(ret == ERROR_SUCCESS)    
	{
	    printf("[%s] post is done\n",__FUNCTION__);
	    return 0;
	}
	if(count++ == 20)
	{
	    return -1;
	}
	systemDelayMs(50);
    }
}
